home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / td-posix / penguin.h
C/C++ Source or Header  |  1998-01-20  |  4KB  |  165 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * "SSSSSYYYMMMETTTTTRIICCC MMMMMMULTIIIIIII PPPPPPENGGGGUIIIIN!!!!!"
  5.   *   -- David S. Miller
  6.   * 
  7.   * Symmetric Multi Penguin support - of course this also works on single
  8.   * penguin machines, but it's kind of pointless there.
  9.   * 
  10.   * This is a rough, simpleminded draft - expect changes when it gets ported 
  11.   * to other systems, and/or rewritten by someone who has experience with this
  12.   * kind of thing. This is just to get started and to see how this works out.
  13.   *
  14.   * Copyright 1997 Bernd Schmidt
  15.   */
  16.  
  17. #include <pthread.h>
  18. #include <semaphore.h>
  19.  
  20. /* Sempahores. We use POSIX semaphores; if you are porting this to a machine
  21.  * with different ones, make them look like POSIX semaphores. */
  22. typedef sem_t uae_sem_t;
  23. #define uae_sem_init sem_init
  24. #define uae_sem_post sem_post
  25. #define uae_sem_wait sem_wait
  26. #define uae_sem_trywait sem_trywait
  27. #define uae_sem_getvalue sem_getvalue
  28.  
  29. typedef union {
  30.     int i;
  31.     void *pv;
  32. } uae_pt;
  33.  
  34. /* These currently require the maximum size to be known at initialization
  35.  * time, but it wouldn't be hard to use a "normal" pipe as an extension once the
  36.  * user-level one gets full.
  37.  * We queue up to chunks pieces of data before signalling the other thread to
  38.  * avoid overhead. */
  39.  
  40. typedef struct {
  41.     uae_sem_t lock;
  42.     uae_sem_t reader_wait;
  43.     uae_sem_t writer_wait;
  44.     uae_pt *data;
  45.     int size, chunks;
  46.     volatile int rdp, wrp;
  47.     volatile int writer_waiting;
  48.     volatile int reader_waiting;
  49. } smp_comm_pipe;
  50.  
  51. static __inline__ void init_comm_pipe (smp_comm_pipe *p, int size, int chunks)
  52. {
  53.     p->data = (uae_pt *)malloc (size*sizeof (uae_pt));
  54.     p->size = size;
  55.     p->chunks = chunks;
  56.     p->rdp = p->wrp = 0;
  57.     p->reader_waiting = 0;
  58.     p->writer_waiting = 0;
  59.     sem_init (&p->lock, 0, 1);
  60.     sem_init (&p->reader_wait, 0, 0);
  61.     sem_init (&p->writer_wait, 0, 0);
  62. }
  63.  
  64. static __inline__ void maybe_wake_reader (smp_comm_pipe *p, int no_buffer)
  65. {
  66.     if (p->reader_waiting
  67.     && (no_buffer || ((p->wrp - p->rdp + p->size) % p->size) >= p->chunks))
  68.     {
  69.     p->reader_waiting = 0;
  70.     sem_post (&p->reader_wait);
  71.     }
  72. }
  73.  
  74. static __inline__ void write_comm_pipe_pt (smp_comm_pipe *p, uae_pt data, int no_buffer)
  75. {
  76.     int nxwrp = (p->wrp + 1) % p->size;
  77.  
  78.     if (p->reader_waiting) {
  79.     /* No need to do all the locking */
  80.     p->data[p->wrp] = data;
  81.     p->wrp = nxwrp;
  82.     maybe_wake_reader (p, no_buffer);
  83.     return;
  84.     }
  85.     
  86.     sem_wait (&p->lock);
  87.     if (nxwrp == p->rdp) {
  88.     /* Pipe full! */
  89.     p->writer_waiting = 1;
  90.     sem_post (&p->lock);
  91.     /* Note that the reader could get in between here and do a
  92.      * sem_post on writer_wait before we wait on it. That's harmless.
  93.      * There's a similar case in read_comm_pipe_int_blocking. */
  94.     sem_wait (&p->writer_wait);
  95.     sem_wait (&p->lock);
  96.     }
  97.     p->data[p->wrp] = data;
  98.     p->wrp = nxwrp;
  99.     maybe_wake_reader (p, no_buffer);
  100.     sem_post (&p->lock);
  101. }
  102.  
  103. static __inline__ uae_pt read_comm_pipe_pt_blocking (smp_comm_pipe *p)
  104. {
  105.     uae_pt data;
  106.  
  107.     sem_wait (&p->lock);
  108.     if (p->rdp == p->wrp) {
  109.     p->reader_waiting = 1;
  110.     sem_post (&p->lock);
  111.     sem_wait (&p->reader_wait);
  112.     sem_wait (&p->lock);
  113.     }
  114.     data = p->data[p->rdp];
  115.     p->rdp = (p->rdp + 1) % p->size;
  116.  
  117.     /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */
  118.     if (p->writer_waiting) {
  119.     p->writer_waiting = 0;
  120.     sem_post (&p->writer_wait);
  121.     }
  122.     sem_post (&p->lock);
  123.     return data;
  124. }
  125.  
  126. static __inline__ int comm_pipe_has_data (smp_comm_pipe *p)
  127. {
  128.     return p->rdp != p->wrp;
  129. }
  130.  
  131. static __inline__ int read_comm_pipe_int_blocking (smp_comm_pipe *p)
  132. {
  133.     uae_pt foo = read_comm_pipe_pt_blocking (p);
  134.     return foo.i;
  135. }
  136.  
  137. static __inline__ void *read_comm_pipe_pvoid_blocking (smp_comm_pipe *p)
  138. {
  139.     uae_pt foo = read_comm_pipe_pt_blocking (p);
  140.     return foo.pv;
  141. }
  142.  
  143. static __inline__ void write_comm_pipe_int (smp_comm_pipe *p, int data, int no_buffer)
  144. {
  145.     uae_pt foo;
  146.     foo.i = data;
  147.     write_comm_pipe_pt (p, foo, no_buffer);
  148. }
  149.  
  150. static __inline__ void write_comm_pipe_pvoid (smp_comm_pipe *p, void *data, int no_buffer)
  151. {
  152.     uae_pt foo;
  153.     foo.pv = data;
  154.     write_comm_pipe_pt (p, foo, no_buffer);
  155. }
  156.  
  157. typedef pthread_t penguin_id;
  158. #define BAD_PENGUIN -1
  159.  
  160. static __inline__ int start_penguin (void *(*f) (void *), void *arg, penguin_id *foo)
  161. {
  162.     return pthread_create (foo, 0, f, arg);
  163. }
  164. #define UAE_PENGUIN_EXIT pthread_exit(0)
  165.